﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Wheels
{
    public static class UriExtensions
    {
#pragma warning disable 1591

        public static Uri CreateUri(this string source)
        {
            return source.GetPossibleUri().FirstOrDefault();
        }

        public static IEnumerable<Uri> GetPossibleUri(this string source)
        {
            if (source.IsNullOrWhiteSpace())
                yield break;

            var old = source;
            Uri result;

            if (Uri.TryCreate(source, UriKind.Absolute, out result))
                yield return result;

            old = source;
            source = source.Trim();
            if (source != old)
            {
                if (Uri.TryCreate(source, UriKind.Absolute, out result))
                    yield return result;
            }

            old = source;
            source = Uri.UnescapeDataString(source);
            if (source != old)
            {
                if (Uri.TryCreate(source, UriKind.Absolute, out result))
                    yield return result;
            }
        }

        public static IEnumerable<Uri> ExtractUriListFromArguments(string query)
        {
            if (query.IsNullOrWhiteSpace())
                yield break;

            if ("?#".Contains(query[0]))
                query = query.Substring(1);

            var args = query.Split('&');

            for (var i = 0; i < args.Length; i++)
            {
                var argText = args[i];
                var uri = argText.CreateUri();
                if (uri == null)
                {
                    var pos = argText.IndexOf('=');
                    if (pos < 0)
                        continue;
                    argText = argText.Substring(pos + 1);

                    uri = argText.CreateUri();
                    if (uri == null)
                        continue;
                }

                yield return uri;

                if (uri.Query.IsNullOrWhiteSpace())
                    continue;

                if (uri.OriginalString == argText)
                {
                    var rest = args.Skip(i + 1).ToArray();
                    var buffer = new StringBuilder(argText, argText.Length + rest.Sum(s => s.Length) + rest.Length);
                    foreach (var s in rest)
                    {
                        buffer.Append('&');
                        buffer.Append(s);
                    }
                    yield return new Uri(buffer.ToString());
                }

                foreach (var inner in uri.ExtractUriList())
                    yield return inner;
            }
        }

        public static IEnumerable<Uri> ExtractUriList(this string source)
        {
            Uri current = source.CreateUri();
            if (current == null)
                return new Uri[0];

            return new[] { current }.Concat(current.ExtractUriList());
        }
        public static IEnumerable<Uri> ExtractUriList(this Uri source)
        {
            var fromQuery = ExtractUriListFromArguments(source.Query);
            var fromHash = ExtractUriListFromArguments(source.Fragment);
            return fromQuery.Concat(fromHash);
        }
    }
}
